package com.alex.util.http;

import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.FutureRequestExecutionService;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @author alex
 */
@Component
public class HttpUtil {
    private static Log logger = LogFactory.getLog(HttpUtil.class);

    @Autowired
    private CloseableHttpClient httpClient;

    @Autowired
    private FutureRequestExecutionService futureRequestExecutionService;

    public <T> T doRequest(HttpRequestBase request, Class<T> clazz) {
        long start = System.currentTimeMillis();
        String stringResponse = doRequest(request);
        T jsonResponse = null;
        try {
            jsonResponse = JSON.parseObject(stringResponse, clazz);
        } catch (Exception e1) {
            logger.error(e1, e1);
            try {
                jsonResponse = new Gson().fromJson(stringResponse, clazz);
            } catch (Exception e2) {
                logger.error("request=" + request + "|timeconsume=" + (System.currentTimeMillis() - start) + "ms |response=" + stringResponse + " |exception=" + e2.getMessage(), e2);
            }
        }
        return jsonResponse;
    }

    public String doRequest(HttpRequestBase request) {

        HttpResponse httpResponse = null;
        String stringResponse = null;
        long start = System.currentTimeMillis();
        try {
            try {
                httpResponse = httpClient.execute(request);
            } catch (IOException e) {
                logger.error("request=" + request + "|timeconsume=" + (System.currentTimeMillis() - start) + "ms |response= |exception=" + e.getMessage(), e);
            }
            if (HttpStatus.SC_OK != httpResponse.getStatusLine().getStatusCode()) {
                logger.error("request=" + request + "|timeconsume=" + (System.currentTimeMillis() - start) + "ms |response= |exception=" + httpResponse.getStatusLine().getReasonPhrase());
            }
            try {
                HttpEntity httpEntity = httpResponse.getEntity();
                stringResponse = EntityUtils.toString(httpEntity, Consts.UTF_8);
            } catch (IOException e) {
                logger.error("request=" + request + "|timeconsume=" + (System.currentTimeMillis() - start) + "ms |response= |exception=" + e.getMessage(), e);
            }

            if (null == stringResponse) {
                logger.error("request=" + request + "|timeconsume=" + (System.currentTimeMillis() - start) + "ms |response= |exception=read response error");
            }
        } finally {
            try {
                request.releaseConnection();
            } catch (Exception e) {
                logger.error(e, e);
            }
        }
        logger.info("request=" + request + "|timeconsume=" + (System.currentTimeMillis() - start) + "ms  |response=" + stringResponse);
        return stringResponse;
    }

    public <T> void doAsyncRequest(final HttpRequestBase request, final Class<T> clazz) {
        doAsyncRequest(request, clazz, true);
    }

    public <T> void doAsyncRequest(final HttpRequestBase request, final Class<T> clazz, final boolean logresponse) {
        final long start = System.currentTimeMillis();
        futureRequestExecutionService.execute(request, null, new ResponseHandler<T>() {
            @Override
            public T handleResponse(HttpResponse httpResponse) throws ClientProtocolException, IOException {
                String stringResponse = null;
                T jsonResponse = null;
                if (HttpStatus.SC_OK != httpResponse.getStatusLine().getStatusCode()) {
                    logger.error("request=" + request + "|timeconsume=" + (System.currentTimeMillis() - start) + "ms |response= |exception=" + httpResponse.getStatusLine().getReasonPhrase());
                    //throw new BizException(BizException.CALL_SERVICE_ERROR, httpResponse.getStatusLine().getReasonPhrase());
                    return null;
                }
                try {
                    HttpEntity httpEntity = httpResponse.getEntity();
                    stringResponse = EntityUtils.toString(httpEntity, Consts.UTF_8);
                } catch (IOException e) {
                    logger.error("request=" + request + "|timeconsume=" + (System.currentTimeMillis() - start) + "ms |response= |exception=" + e.getMessage(), e);
                    //throw new BizException(BizException.CALL_SERVICE_ERROR, e.getMessage());
                    return null;
                }

                if (null == stringResponse) {
                    logger.error("request=" + request + "|timeconsume=" + (System.currentTimeMillis() - start) + "ms |response= |exception=read response error");
                    //throw new BizException(BizException.CALL_SERVICE_ERROR, "read response error");
                    return null;
                }

                try {
                    jsonResponse = JSON.parseObject(stringResponse, clazz);
                } catch (Exception e1) {
                    logger.error("request=" + request + "|timeconsume=" + (System.currentTimeMillis() - start) + "ms |response=" + stringResponse + " |exception=" + e1.getMessage(), e1);
                }
                return jsonResponse;
            }
        });
    }
}
